﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using Model;

namespace WindowsTest
{
    public class ImageOprationClass
    {
        /// <summary>
        /// 图片刮花方法（横向）
        /// </summary>
        /// <param name="bitmap">输入的二值图像</param>
        /// <returns>输出的目标图像</returns>
        public unsafe static Bitmap BlacklRow(Bitmap bitmap)
        {
            int width = bitmap.Width;
            int height = bitmap.Height;
            var rectTemp = new Rectangle(0, 0, width, height);
            BitmapData bmpData = bitmap.LockBits(rectTemp, ImageLockMode.ReadWrite, bitmap.PixelFormat);
            var bitmapSave = new Bitmap(width, height, bitmap.PixelFormat);
            BitmapData bmpDataTemp = bitmapSave.LockBits(rectTemp, ImageLockMode.ReadWrite,
                bitmapSave.PixelFormat);
            var ptrSave = (byte*)bmpDataTemp.Scan0.ToPointer();
            int strideSave = bmpData.Stride;
            FillWhite(ptrSave, height, strideSave);

            var ptr = (byte*)bmpData.Scan0.ToPointer();
            var ints = new int[height * width];

            fixed (int* ptrInt = &ints[0])
            {
                for (int i = 0; i < height; i++)
                {
                    for (int j = 1; j < width - 1; j++)
                    {
                        int temp = *(ptr + i * strideSave + (j >> 3)) >> (j & 7 ^ 7) & 1;//这句是什么意思？
                        if (temp == 0)
                            *(ptrInt + i * width + j) = 1;
                    }
                }
                const int w = 15;

                for (int i = 0; i < height; i++)
                {
                    for (int j = 0; j < width; j++)
                    {
                        for (int k = 0; k < w; k++)
                        {
                            int temp1 = j + k >= width ? width - 1 : j + k;
                            int tempNum = i * width + temp1;
                            if (*(ptrInt + tempNum) > 0)
                            {
                                for (int n = 0; n < w; n++)
                                {
                                    int tempN = j - n > 0 ? j - n : 0;
                                    int tempNumn = i * width + tempN;
                                    if (*(ptrInt + tempNumn) > 0)
                                    {
                                        int temp = *(ptrSave + i * strideSave + (j >> 3)) & (255 ^ (1 << (j & 7 ^ 7)));//这句是什么意思？
                                        *(ptrSave + i * strideSave + (j >> 3)) = (byte)temp;
                                        goto loop;
                                    }
                                }

                            }
                        }
                    loop:
                        ;
                    }
                }
            }

            bitmapSave.UnlockBits(bmpDataTemp);
            bitmap.UnlockBits(bmpData);

            bitmapSave.SetResolution(200, 200);//设置DPI

            return bitmapSave;
        }

        /// <summary>
        /// 检测横向黑色区域的直线
        /// </summary>
        /// <param name="ta">影像的二维数组</param>
        /// <param name="minlength">直线段的最小长度</param>
        /// <param name="maxlength">直线段的最大长度</param>
        /// <param name="minY">识别区域的上边界</param>
        /// <param name="maxY">识别区域的下边界</param>
        /// <returns>识别区域内的所有符合条件的直线段</returns>
        public static unsafe List<Line> HorizontalBlackAreaLine(int minlength, int maxlength, int minY, int maxY, int[,] ta)
        {
            List<Line> verticalLine = new List<Line>();
            int imgWidth = ta.GetLength(0);

            fixed (int* ptr = &ta[0, 0])
            {
                for (int i = 0; i < imgWidth; i++)
                {
                    for (int j = minY; j < maxY; j++)
                    {
                        if (*(ptr + j * imgWidth + i) == 1)
                        {
                            Line lineInfo = new Line();
                            lineInfo.B_Min = j;
                            lineInfo.B_Max = j;
                            bool flag = true;
                            while (flag)
                            {
                                flag = false;
                                for (int k = 0; k <= 0; k++)
                                {
                                    j++;
                                    if (j >= maxY)
                                    {
                                        break;
                                    }
                                    if (*(ptr + j * imgWidth + i) == 1)
                                    {
                                        flag = true;
                                        lineInfo.B_Max = j;
                                        break;
                                    }
                                }
                            }
                            int length = lineInfo.B_Max - lineInfo.B_Min;
                            if (length > minlength && length < maxlength)
                            {
                                lineInfo.A = i;
                                verticalLine.Add(lineInfo);
                            }
                        }
                    }
                }
            }

            return verticalLine;
        }

        /// <summary>
        /// 检测纵向黑色区域的直线
        /// </summary>
        /// <param name="ta">影像的二维数组</param>
        /// <param name="minlength">直线段最小长度</param>
        /// <param name="maxlength">直线段最大长度</param>
        /// <param name="minX">识别区域的左边界</param>
        /// <param name="maxX">识别区域的右边界</param>
        /// <returns>识别区域内的所有符合条件的直线段</returns>
        public static unsafe List<Line> VerticalBlackAreaLine(int minlength, int maxlength, int minX, int maxX, int[,] ta)
        {
            int imgHeight = ta.GetLength(1);
            int imgWidth = ta.GetLength(0);
            List<Line> horizontalLine = new List<Line>();

            fixed (int* ptr = &ta[0, 0])
            {
                for (int i = 0; i < imgHeight; i++)
                {
                    for (int j = minX; j < maxX; j++)
                    {
                        if (*(ptr + i * imgWidth + j) == 1)
                        {
                            Line lineInfo = new Line();
                            lineInfo.B_Min = j;
                            lineInfo.B_Max = j;
                            bool flag = true;
                            while (flag)
                            {
                                flag = false;
                                for (int k = 0; k <= 0; k++)
                                {
                                    j++;
                                    if (j >= maxX)
                                    {
                                        break;
                                    }
                                    if (*(ptr + i * imgWidth + j) == 1)
                                    {
                                        flag = true;
                                        lineInfo.B_Max = j;
                                        break;
                                    }
                                }
                            }
                            int length = lineInfo.B_Max - lineInfo.B_Min;
                            if (length > minlength && length < maxlength)
                            {
                                lineInfo.A = i;
                                horizontalLine.Add(lineInfo);
                            }
                        }
                    }
                }
            }

            return horizontalLine;
        }

        /// <summary>
        /// 游程检测直线得出黑色区域
        /// </summary>
        /// <param name="listLine">检测到的所有直线段</param>
        /// <param name="minLength">最小直线段长度</param>
        /// <param name="maxbreak">最大允许断开</param>
        /// <returns>黑边的直线段列表</returns>
        public static List<Line> YC_BlackArea(List<Line> listLine, int minLength, int maxbreak)
        {
            List<List<Line>> listBlackArea = new List<List<Line>>();

            List<Line> returnData = new List<Line>();

            for (int i = 0; i < listLine.Count; i++)
            {
                Line temp = new Line();
                temp.A = listLine[i].A;
                temp.B_Max = listLine[i].B_Max;
                temp.B_Min = listLine[i].B_Min;
                returnData.Add(listLine[i]);
                for (int j = i + 1; j < listLine.Count; j++)
                {
                    bool flagBreak = listLine[j].A > temp.A + maxbreak;
                    if (!flagBreak)
                    {
                        bool flag = (listLine[j].A > temp.A) && ((listLine[j].B_Min >= temp.B_Min && listLine[j].B_Min < temp.B_Max) || (listLine[j].B_Min < temp.B_Min && listLine[j].B_Max > temp.B_Min));
                        if (flag)
                        {
                            temp.A = listLine[j].A;
                            temp.B_Max = listLine[j].B_Max;
                            temp.B_Min = listLine[j].B_Min;
                            returnData.Add(listLine[j]);
                        }
                    }
                    else
                    {
                        break;
                    }
                }
                bool flag_Temp = returnData[returnData.Count - 1].A - returnData[0].A > minLength;
                if (flag_Temp)
                {
                    break;
                }
                else
                {
                    listBlackArea.Add(returnData);
                    returnData.Clear();
                    continue;
                }
            }

            return returnData;
        }

        /// <summary>
        /// 图片顺时针旋转90°
        /// </summary>
        /// <param name="bitmap">输入的图像</param>
        /// <returns>输出的目标图像</returns>
        public static Bitmap ImageGoRound(Bitmap bitmap)
        {
            bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone);
            bitmap.SetResolution(200, 200);
            return bitmap;
        }

        private unsafe static void FillWhite(byte* ptr, int height, int stride)
        {
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < stride; j++)
                {
                    *(ptr + i * stride + j) = 255;
                }
            }
        }

        #region 获取二值二维数组

        /// <summary>
        /// 获取1位图像二值数组
        /// </summary>
        /// <param name="bmp">位图影像</param>
        /// <returns>二值数组</returns>
        public static int[,] GetArray1Bit(Bitmap bmp)
        {
            int iw = bmp.Width;
            int ih = bmp.Height;
            var rect = new Rectangle(0, 0, iw, ih);
            BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);
            var returnData = new int[iw, ih];
            int stride = bmpData.Stride;
            unsafe
            {
                var ptr = (byte*)(bmpData.Scan0.ToPointer());
                fixed (int* imgPtrTemp = &returnData[0, 0])
                {
                    for (int i = 0; i < ih; i++)
                    {
                        int j = 0;
                        var ptrLine = (byte*)((IntPtr)ptr).ToPointer();
                        while (j < iw)
                        {
                            bool flag = true;
                            for (int k = 0; k < 8; k++)
                            {
                                if (j < iw)
                                {
                                    int point = ptrLine[0];//包含8个像素的颜色代码
                                    int color = (point >> (j & 7 ^ 7)) & 1;//取出j的颜色代码
                                    if (color == 0)//颜色代码0，表示黑色
                                        *(imgPtrTemp + i * iw + j) = 1;
                                }
                                else
                                {
                                    flag = false;
                                    break;
                                }
                                j++;
                            }
                            if (flag)
                                ptrLine++;
                        }
                        ptr += stride;
                    }
                }
            }
            bmp.UnlockBits(bmpData);

            return returnData;
        }

        /// <summary>
        /// 获取24位图像二值数组
        /// </summary>
        /// <param name="bmp">位图影像</param>
        /// <param name="limitColor">二值的限制数值</param>
        /// <returns></returns>
        public static int[,] GetArray24Bit(Bitmap bmp, int limitColor)
        {
            int iw = bmp.Width;
            int ih = bmp.Height;
            var rectTemp = new Rectangle(0, 0, iw, ih);
            // 将Bitmap锁定到系统内存中
            BitmapData bmpData = bmp.LockBits(rectTemp, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            var ta = new int[iw, ih];

            unsafe
            {
                var ptr = (byte*)(bmpData.Scan0.ToPointer());
                fixed (int* ptrTemp = &ta[0, 0])
                {
                    for (int i = 0; i < ih; i++)
                    {
                        for (int j = 0; j < iw; j++)
                        {
                            int grey = (ptr[0] * 28 + ptr[1] * 151 + ptr[2] * 77) >> 8;
                            ptr += 3;
                            if (grey < limitColor)
                            {
                                *(ptrTemp + i * iw + j) = 1;
                            }
                        }
                        ptr += bmpData.Stride;
                    }
                }
            }
            //解锁位图
            bmp.UnlockBits(bmpData);

            return ta;
        }

        /// <summary>
        /// 获取8位图像二值数组
        /// </summary>
        /// <param name="bmp">位图影像</param>
        /// <param name="limitColor">二值的限制数值</param>
        /// <returns></returns>
        public static int[,] GetArray8Bit(Bitmap bmp, int limitColor)
        {
            int iw = bmp.Width;
            int ih = bmp.Height;
            var rectTemp = new Rectangle(0, 0, iw, ih);
            // 将Bitmap锁定到系统内存中
            BitmapData bmpData = bmp.LockBits(rectTemp, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

            var ta = new int[iw, ih];

            unsafe
            {
                var ptr = (byte*)(bmpData.Scan0.ToPointer());
                fixed (int* ptrTemp = &ta[0, 0])
                {
                    for (int i = 0; i < ih; i++)
                    {
                        var ptrLine = (byte*)((IntPtr)ptr).ToPointer();
                        for (int j = 0; j < iw; j++)
                        {
                            int grey = ptrLine[0];
                            ptrLine += 1;
                            if (grey < limitColor)
                            {
                                *(ptrTemp + i * iw + j) = 1;
                            }
                        }
                        ptr += bmpData.Stride;
                    }
                }
            }
            //解锁位图
            bmp.UnlockBits(bmpData);

            return ta;
        }

        #endregion
    }
}
